さあ、敵が表示出来たら敵の移動と自機弾との当たり判定をしてみましょう♪
まず『*MAIN』メインルーチンですが、ココにまたも1つサブルーチン『gosub
*TEKIMOVE』を追加します。このサブルーチンで敵の移動と当たり判定を行います。また、敵の初期描画『*TEKI』はゲームの初め、もしくは2面等の面の初めにしか必要がないので、『if
enemy=0 : gosub *TEKI』この様に敵が画面に一度も表示されていなければ『enemy=0』サブルーチンに飛ぶようにして、それ以外では『*TEKI』サブルーチンには飛ばないように変更します。
次に『*TEKI』の所ですが、初期描画が終わったら『enemy=1』フラッグを立てて以後このサブルーチンに飛ばないようにします。
次に『*TEKIMOVE』ココからが今回のメイン。
まず、敵は複数(今回は12機)存在するので『repeat〜loop』を使用して表示する敵の数だけループさせます。
次の『ef.cnt<1
: continue』ですが、敵が存在しなければ以後の移動・当たり判定を飛ばすという意味です。
次に、画面の左右に表示されている敵を対照的に移動させる為にシステム変数『cnt』を利用して別々の計算処理をするように振り分けています。
さあ、この後が重要なのですが、自機弾と敵の当たり判定を行う為に二重ループを利用します。(要するに敵12機の1機づつに対して×自機弾2発の1発づつをそれぞれ当たり判定をする=24回の処理をするわけです。当然、敵の数や自機弾の数が増えればこの処理も多くなり、ゲーム全体のスピードに大きく影響してきます。)二重ループを使う場合注意が必要なのですが『repeat〜loop』の回数を数える為に使うシステム関数『cnt』ですが、外側のループでは外側だけの・内側のループでは内側だけの関数になってしまい、内側のループから見て外側のループが今何回目なのかが分からなくなってしまうのです。
そこで外側のループが何回目なのか記憶しておく必要があります。これを『ent=cnt』この様にして変数entに代入しておきます。これで内側のループから見て『ent』は外側(敵)の番号になります。
次に当たり判定ですが、敵の座標から自機弾の座標を引いて絶対値を出します。この絶対値の値が一定範囲以内になったら衝突処理をします。
具体的に『dx=(ex.ent+16)-(sx.cnt+16)』この部分ですが、今回敵キャラも自機弾も32*32の大きさなので敵(ex,ey)・自機弾(sx,sy)の座標にキャラの大きさの半分を足す事でその中心座標が分かります。この敵キャラの中心座標から自機弾の中心座標を引いています。その後『if
dx<0 : dx=-dx』差がマイナスだった場合にプラスに変換(絶対値に)しています。Y座標も同様に行います。
その後『if
dx<10 : if dy<10』もし、絶対値がこの範囲内になったなら衝突処理を行います。(↓下図参照)
 |
敵の中心座標(ex+16,ey+16)から自機弾の中心座標(sx+16,sy+16)を引いて、その差が10以内になったら衝突判定をする。
ちなみに、絶対値を大きくすれば当る範囲が大きくなるし、小さくすれば範囲も狭まります。これは、キャラクタの形状の問題(見た目では当たっていないのに当たってしまったり)や難易度を決める上でとても重要な事ですから、何度も試しながら丁度良い値をご自分でお探し下さい。 |
衝突処理ですが『ef.cnt-
: sf.cnt-』で敵と自機弾を消滅させています。その後、敵の居た場所に『●』爆風の代わりを表示します。
敵の移動・当たり判定を終えた後に存在する敵を新しい座標に描画をしてこのルーチンも終わりです。
今回はスクリプトが短い割りには結構難しく(と言うより説明がややこしく)なっていますが、お分かりいただけたでしょうか!? この二重ループの注意と当たり判定の原理さえ憶えてしまえば、この先キャラクターが増えても全て同じ事ですので、ラクチンになりますよ♪
下記のスクリプトの一部または全部において転用は自由とさせていただきますので、色々と数字を換えてお試し下さい♪
下記スクリプトをHSPのスクリプトエディターにコピペでお使いいただけます。
|
#define SHOTMAX 2 ;自機弾最大数
#define ENEMYMAX 12 ;敵機最大数
buffer 2,,,1
picload "cruiser.bmp"
screen 0,640,480,1,dispx-640/2,dispy-480/2:cls 4 : title "space cruiser"
font "MS 明朝",20
gmode 2
*SYOKIKA
mx=300 : my=400 ;自機の初期位置
lv=1 ;初期レベル
dim sf,SHOTMAX ;自弾の有無
dim sx,SHOTMAX ;自弾のX座標
dim sy,SHOTMAX ;自弾のY座標
dim ef,ENEMYMAX ;敵の硬さ
dim ex,ENEMYMAX ;敵のX座標
dim ey,ENEMYMAX ;敵のY座標
dim et,ENEMYMAX ;敵発生からのカウンター
dim esx,ENEMYMAX ;敵のX軸移動量
dim esy,ENEMYMAX ;敵のY軸移動量
*MAIN ;メインループ
palcolor 0 : boxf 0,0,640,480
gosub *JIKI
gosub *TAMA
if enemy=0 : gosub *TEKI
gosub *TEKIMOVE
redraw 1 : redraw 2 : await 30
goto *MAIN
*JIKI ;自機の移動・ショットキーチェック
stick bt,5 : k- : if k<1 : if bt&16 : ff=1 : k=3
mxv=(bt&4!0):mxv-=(bt&1!0)
mx+=mxv*8
if mx<0 : mx=0
if mx>580 : mx=580
pos mx,my : gcopy 2,0,32,64,64
return
*TAMA ;自機弾の移動・表示
repeat SHOTMAX
if ff>0 : if sf.cnt=0 : ff- : sf.cnt=1 : sx.cnt=mx+16 : sy.cnt=my-20
if sf.cnt=0 : continue
sy.cnt-=12 : if sy.cnt<-32 : sf.cnt=0
pos sx.cnt,sy.cnt : gcopy 2,96,0,32,32
loop
return
*TEKI ;敵の出現
repeat ENEMYMAX
if cnt<12 {
if cnt<10 {
if cnt<8 {
if cnt<6 {
if cnt<4 {
if cnt<2 { ef.cnt=1 : ex.cnt=cnt*100+100 : ey.cnt=80
pos ex.cnt,ey.cnt : gcopy 2,lv*32,0,32,32
}else{ ef.cnt=1 : ex.cnt=cnt-2*100+100 : ey.cnt=130
pos ex.cnt,ey.cnt : gcopy 2,lv*32,0,32,32 }
}else{ ef.cnt=1 : ex.cnt=cnt-4*100+100 : ey.cnt=180
pos ex.cnt,ey.cnt : gcopy 2,lv*32,0,32,32 }
}else{ ef.cnt=1 : ex.cnt=cnt-5*100+300 : ey.cnt=80
pos ex.cnt,ey.cnt : gcopy 2,lv*32,0,32,32 }
}else{ ef.cnt=1 : ex.cnt=cnt-7*100+300 : ey.cnt=130
pos ex.cnt,ey.cnt : gcopy 2,lv*32,0,32,32 }
}else{ ef.cnt=1 : ex.cnt=cnt-9*100+300 : ey.cnt=180
pos ex.cnt,ey.cnt : gcopy 2,lv*32,0,32,32 }
}
esx.cnt=5 : esy.cnt=5 : et.cnt=0
enemy=1
loop
return
*TEKIMOVE ;敵の移動処理・当たり判定
repeat ENEMYMAX
if ef.cnt<1 : continue
et.cnt++
if cnt<6 {
ex.cnt-=esx.cnt : if et.cnt>20 : et.cnt=-20 : esx.cnt=-esx.cnt
ey.cnt+=esy.cnt : if (ey.cnt>200)|(ey.cnt<50) : esy.cnt=-esy.cnt
}else{
ex.cnt+=esx.cnt : if et.cnt>20 : et.cnt=-20 : esx.cnt=-esx.cnt
ey.cnt+=esy.cnt : if (ey.cnt>200)|(ey.cnt<50) : esy.cnt=-esy.cnt
}
ent=cnt
repeat SHOTMAX
if sf.cnt=0 : continue
dx=(ex.ent+16)-(sx.cnt+16) : if dx<0 : dx=-dx
dy=(ey.ent+16)-(sy.cnt+16) : if dy<0 : dy=-dy
if dx<10 : if dy<10 {
ef.ent- : sf.cnt- : pos ex.ent,ey.ent : palcolor 255 : mes "●"
}
loop
pos ex.cnt,ey.cnt : gcopy 2,lv*32,0,32,32
loop
return
|
|
 ↑こんな感じです。敵移動と当たり判定追加♪
ようやくゲームらしくなってきましたね(^^);
|
上手く出来たら、次に行ってみましょう♪
NEXT ->>
|